// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// V [author] rhyme_lph
// z [email]  rhymelph@gmail.com
// S [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/entities/product_entity.dart';
import 'package:finance_app/src/entities/services_entity.dart';
import 'package:finance_app/src/entities/setting_data_entity.dart';
import 'package:finance_app/src/http_service/http_coa_service.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/page/setting/account/new_account_page.dart';
import 'package:finance_app/src/provider/setting/chart_of_accounts_provider.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/currency_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/date_time_select_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:flutter/material.dart';

class NewAccountProvider extends BaseProvider with InitEditDataMixin {
  TextEditingController accountNameController = TextEditingController();
  FocusNode accountNameFocusNode = FocusNode();

  TextEditingController accountCodeController = TextEditingController();
  FocusNode accountCodeFocusNode = FocusNode();

  TextEditingController accountDescriptionController = TextEditingController();
  FocusNode accountDescriptionFocusNode = FocusNode();
  TextEditingController priceController = TextEditingController();
  FocusNode priceFocusNode = FocusNode();
  CoaCoaAccountHeaderCoaAccountDetail parentAccount;

  int get parentAccountId => parentAccount?.id;

  bool isEditDisallowed = false;

  List<String> menuList = ['Edit', 'Delete'];

  DateTime asAt;

  SettingDataCurrency unit;

  List<ServicesEntity> serviceList = [];
  List<ProductEntity> productList = [];

  bool get isShowProductLink =>
      (parentAccount?.name == 'Product Sales') && !isEditDisallowed;

  bool get isShowServiceLink =>
      (parentAccount?.name == 'Service Revenue') && !isEditDisallowed;

  void unFocus() {
    accountNameFocusNode.unfocus();
    accountCodeFocusNode.unfocus();
    accountDescriptionFocusNode.unfocus();
    priceFocusNode.unfocus();
  }

  @override
  void dispose() {
    super.dispose();
    accountNameController.dispose();
    accountNameFocusNode.dispose();
    accountCodeController.dispose();
    accountCodeFocusNode.dispose();
    accountDescriptionController.dispose();
    accountDescriptionFocusNode.dispose();
    priceController.dispose();
    priceFocusNode.dispose();
  }

  @override
  Future get dataFuture => null;

  void onChangeCurrency() {
    unFocus();
    obtainContext?.call((context) async {
      unit = await showCurrencyBottomSheet(context, unit);
      update();
    });
  }

  void onChangeParentAccount() async {
    unFocus();
    final result = await Routes.navigateTo(
        RouterGenProviders.chartOfAccountsPage,
        params: {
          'isSelectMode': true,
          'editId': id,
        });
    if (result != null) {
      parentAccount = result;
      loadSuggestNumber();
      update();
    }
  }

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        onDelete();
        break;
    }
  }

  void onDelete() async {
    obtainContext?.call((context) async {
      bool isSuccess = await showDeleteCoaInfoBottomSheet(context);
      if (isSuccess == true) {
        isSuccess = false;
        await post(HttpCoaService.deleteCoa(id),
            loadingTip: S.current.loading,
            autoHandler: AutoHandler.Toast, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess == true) {
          final chartPro = Providers.get<ChartOfAccountsProvider>(
              RouterGenProviders.chartOfAccountsPage, null);
          if (chartPro != null) {
            chartPro.onTry();
          }
          await showCoaSuccessBottomSheet(context);

          Navigator.of(context).pop();
        }
      }
    });
  }

  void onSave() async {
    if (numberHasError == true) return;
    unFocus();
    String name = accountNameController.text;
    String code = accountCodeController.text;
    String currencyCode = unit?.key;
    String price = priceController?.text;
    String asAtString = DateTimeUtils.formatDateTime(asAt, 'yyyy-MM-dd');
    String description = accountDescriptionController.text;

    CoaCoaAccountHeaderCoaAccountDetail entity;
    List map = [];
    if (productList.length != 0) {
      map = productList.map((e) => {'type': 'product', 'id': e.id}).toList();
    } else if (serviceList.length != 0) {
      map = serviceList.map((e) => {'type': 'service', 'id': e.id}).toList();
    }

    if (id == null) {
      await post(
          HttpCoaService.createCoa(
            name: name,
            currency_code: currencyCode,
            external_account_code: code,
            parent_account_id: parentAccount?.id ?? 0,
            // open_balance: num.parse(price, (e) => null),
            open_balance: 0,
            as_at: asAtString,
            description: description,
            map: map,
          ),
          autoHandler: AutoHandler.Toast,
          loadingTip: S.current.loading, onSuccess: (result) {
        entity =
            getEntityFromResult<CoaCoaAccountHeaderCoaAccountDetail>(result);
      });
      initWidgetData(entity, parentAccount);
      update();
    } else {
      await post(
          HttpCoaService.updateCoa(
            id,
            name: name,
            currency_code: currencyCode,
            external_account_code: code,
            parent_account_id: parentAccount?.id ?? 0,
            // open_balance: num.parse(price, (e) => null),
            open_balance: 0,
            as_at: asAtString,
            description: description,
            map: map,
          ),
          autoHandler: AutoHandler.Toast,
          loadingTip: S.current.loading, onSuccess: (result) {
        entity =
            getEntityFromResult<CoaCoaAccountHeaderCoaAccountDetail>(result);
      });
    }
    if (entity != null) {
      final chartPro = Providers.get<ChartOfAccountsProvider>(
          RouterGenProviders.chartOfAccountsPage, null);
      if (chartPro != null) {
        chartPro.onTry();
      }
      initWidgetData(entity, parentAccount);
      update();
    }
  }

  void onChangeAsAt() {
    unFocus();
    obtainContext?.call((context) async {
      final result =
          await showDateTimeSelectBottomSheet(context, S.current.as_at, asAt);
      if (result != null) {
        asAt = result;
        update();
      }
    });
  }

  void initWidgetData(CoaCoaAccountHeaderCoaAccountDetail data,
      CoaCoaAccountHeaderCoaAccountDetail parentData) {
    if (data == null) return;
    init(data.id);
    parentAccount = parentData;
    accountCodeController.text = data.externalAccountCode;
    accountNameController.text = data.name;
    accountDescriptionController.text = data.description;
    isEditDisallowed = data.editDisallowed;
    priceController.text = data.balance.toString();
    asAt = DateTimeUtils.toDateTime(data.asAt, 'yyyy-MM-dd');
    if (data.maps != null) {
      List<ServicesEntity> services = [];
      List<ProductEntity> products = [];
      for (final item in data.maps) {
        if (item['map_type'] == 'service') {
          services.add(ServicesEntity()..id = item['map_id']);
        } else if (item['map_type'] == 'product') {
          products.add(ProductEntity()..id = item['map_id']);
        }
      }
      serviceList = services;
      productList = products;
    }
  }

  @override
  Future get editDataFuture => dataFuture;

  @override
  TextEditingController get numberCtl => accountCodeController;

  @override
  String get type => 'coa';

  void onLinkedProducts() async {
    unFocus();
    final result =
        await Routes.navigateTo(RouterGenProviders.linkedProductsPage, params: {
      'selects': productList,
    });
    if (result != null) {
      productList = result;
      update();
    }
  }

  void onLinkedService() async {
    unFocus();
    final result =
        await Routes.navigateTo(RouterGenProviders.linkedServicesPage, params: {
      'selects': serviceList,
    });
    if (result != null) {
      serviceList = result;
      update();
    }
  }
}
